using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web.UI;
using DotNetNuke.Entities.Tabs;

namespace HeroldIT.Dnn.SkinObjects
{
    /// <summary>
    /// A SkinObject for generating a breadcrumb.
    /// </summary>
    [DefaultProperty("Prefix")]
    public class Breadcrumb : BreadcrumbBase
    {
        #region static methods

        /// <summary>
        /// Gets the all instances of <see cref="Breadcrumb"/> controls on the page.
        /// </summary>
        /// <param name="page">The page to look on.</param>
        /// <returns>A list of <see cref="Breadcrumb"/> controls on the page, or <c>null</c> if none are present.</returns>
        public static IList<Breadcrumb> GetBreadcrumbsFor(Page page)
        {
            if (null == page)
                throw new ArgumentNullException("page");

            return page.Items[typeof (Breadcrumb)] as IList<Breadcrumb>;
        }

        #endregion

        #region properties

        /// <summary>
        /// Whether to use the TabName instead of Title for displaying. Default is <c>true</c>.
        /// </summary>
        [Browsable(true)]
        [Category("Behavior")]
        [DefaultValue(true)]
        [Localizable(false)]
        public new bool UseTabName
        {
            get { return base.UseTabName; }
            set { base.UseTabName = value; }
        }

        private string partCssClass = String.Empty;

        /// <summary>
        /// The css class to use for the breadcrumb's parts.
        /// </summary>
        /// <remarks>
        /// Setting a value makes the tab names or titles be rendered in a &lt;span&gt; with the given class name.
        /// </remarks>
        [Browsable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string PartCssClass
        {
            get { return this.partCssClass; }
            set { this.partCssClass = value; }
        }

        private string linkCssClass = String.Empty;

        /// <summary>
        /// The css class to use for the breadcrumb's links.
        /// </summary>
        /// <remarks>
        /// Setting a value makes the links have the given class name. The items are contained in the links, also including the span, if <see cref="PartCssClass"/> is set.
        /// </remarks>
        [Browsable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string LinkCssClass
        {
            get { return this.linkCssClass; }
            set { this.linkCssClass = value; }
        }

        private string separatorCssClass = String.Empty;

        /// <summary>
        /// The css class to use for the breadcrumb's separator.
        /// </summary>
        /// <remarks>
        /// Setting a value makes the separators be rendered in a &lt;span&gt; with the given class name.
        /// </remarks>
        [Browsable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string SeparatorCssClass
        {
            get { return this.separatorCssClass; }
            set { this.separatorCssClass = value; }
        }

        #endregion

        #region constructors

        /// <summary>
        /// Creates a new Breadcrumb SkinObject.
        /// </summary>
        public Breadcrumb()
        {
            base.UseTabName = true;
        }

        #endregion

        #region page lifecycle

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Init" /> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs" /> object that contains the event data.</param>
        protected override void OnInit(EventArgs e)
        {
            if (null != this.Page)
            {
                IList<Breadcrumb> breadcrumbs = GetBreadcrumbsFor(this.Page);
                if (null == breadcrumbs)
                {
                    this.Page.Items[typeof (Breadcrumb)] = new List<Breadcrumb> {this};
                }
                else
                {
                    breadcrumbs.Add(this);
                }
            }

            base.OnInit(e);
        }

        /// <summary>
        /// Renders the control.
        /// </summary>
        /// <param name="writer">The writer to which to render the control.</param>
        protected override void Render(HtmlTextWriter writer)
        {
            TabInfo[] parts = this.GetBreadcrumbPartsToDisplay();

            string prefix = this.GeneratePrefix();
            if (!String.IsNullOrEmpty(prefix) && (this.PrefixType == PrefixType.HomeTabName || this.PrefixType == PrefixType.HomeTabTitle) && this.PortalSettings.ActiveTab.TabID.Equals(this.HomeTab.TabID))
            {
                this.RenderPrefix(writer, prefix);
                return;
            }

            if (this.ReverseDirection)
            {
                this.RenderReverse(writer, parts, prefix);
            }
            else
            {
                this.RenderForward(writer, parts, prefix);
            }
        }

        #endregion

        #region methods

        private void RenderPart(HtmlTextWriter writer, string text)
        {
            bool renderSpan = !String.IsNullOrEmpty(this.partCssClass);
            if (renderSpan)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, this.partCssClass, true);
                writer.RenderBeginTag(HtmlTextWriterTag.Span);
            }
            writer.Write(text);
            if (renderSpan)
            {
                writer.RenderEndTag();
            }
        }

        private void RenderLink(HtmlTextWriter writer, string url, string text)
        {
            if (!String.IsNullOrEmpty(this.linkCssClass))
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, this.linkCssClass, true);
            }
            writer.AddAttribute(HtmlTextWriterAttribute.Href, url, true);
            writer.RenderBeginTag(HtmlTextWriterTag.A);
            RenderPart(writer, text);
            writer.RenderEndTag();
        }

        private bool RenderTab(HtmlTextWriter writer, TabInfo tab)
        {
            BreadcrumbEventArgs e = this.GetRenderInfo(tab);
            if (!e.OmitBreadcrumbPart)
            {
                this.RenderTab(writer, tab, e);
                return true;
            }
            return false;
        }

        private void RenderTab(HtmlTextWriter writer, TabInfo tab, BreadcrumbEventArgs e)
        {
            if (tab.IsVisible)
            {
                this.RenderLink(writer, e.UrlToRender, e.NameToRender);
            }
            else
            {
                this.RenderPart(writer, e.NameToRender);
            }
        }

        private void RenderSeparator(HtmlTextWriter writer)
        {
            bool renderSpan = !String.IsNullOrEmpty(this.separatorCssClass);
            if (renderSpan)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, this.separatorCssClass);
                writer.RenderBeginTag(HtmlTextWriterTag.Span);
            }
            writer.Write(this.Separator);
            if (renderSpan)
            {
                writer.RenderEndTag();
            }
        }

        private void RenderPrefix(HtmlTextWriter writer, string prefix)
        {
            if (!String.IsNullOrEmpty(prefix))
            {
                switch (this.PrefixType)
                {
                    case PrefixType.DomainName:
                    case PrefixType.PortalName:
                        this.RenderLink(writer, this.Request.Url.GetLeftPart(UriPartial.Authority), prefix);
                        break;

                    case PrefixType.HomeTabName:
                    case PrefixType.HomeTabTitle:
                        this.RenderLink(writer, this.HomeTab.FullUrl, prefix);
                        break;

                    case PrefixType.CustomPrefix:
                        this.RenderPart(writer, prefix);
                        break;
                }
            }
        }

        private void RenderForward(HtmlTextWriter writer, TabInfo[] parts, string prefix)
        {
            bool renderSeparator = false;
            if (!String.IsNullOrEmpty(prefix))
            {
                RenderPrefix(writer, prefix);
                renderSeparator = true;
            }
            for (int i = 0; i < parts.Length; i++)
            {
                TabInfo part = parts[i];
                BreadcrumbEventArgs bea = this.GetRenderInfo(part);
                if (!bea.OmitBreadcrumbPart)
                {
                    if (renderSeparator)
                    {
                        RenderSeparator(writer);
                    }
                    this.RenderTab(writer, part);
                    renderSeparator = true;
                }
            }
            TabInfo activeTab = this.UsePageLocalization ? Localizer.LocalizeTab(this.PortalSettings.ActiveTab) : this.PortalSettings.ActiveTab;
            BreadcrumbEventArgs e = this.GetRenderInfo(activeTab);
            if (!e.OmitBreadcrumbPart)
            {
                if (renderSeparator)
                {
                    RenderSeparator(writer);
                }
                this.RenderTab(writer, activeTab, e);
            }
        }

        private void RenderReverse(HtmlTextWriter writer, TabInfo[] parts, string prefix)
        {
            bool renderSeparator = this.RenderTab(writer, this.UsePageLocalization ? Localizer.LocalizeTab(this.PortalSettings.ActiveTab) : this.PortalSettings.ActiveTab);
            for (int i = parts.Length - 1; i >= 0; i--)
            {
                TabInfo part = parts[i];

                BreadcrumbEventArgs e = this.GetRenderInfo(part);
                if (!e.OmitBreadcrumbPart)
                {
                    if (renderSeparator)
                    {
                        this.RenderSeparator(writer);
                    }
                    this.RenderTab(writer, part, e);
                    renderSeparator = true;
                }
            }
            if (!String.IsNullOrEmpty(prefix))
            {
                if (renderSeparator)
                {
                    RenderSeparator(writer);
                }
                RenderPrefix(writer, prefix);
            }
        }

        #endregion
    }
}
